﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using etcetera.Mvc.UI.Grid;
using MvcContrib.UI.Grid;

namespace etcetera.Mvc.UI.Toolbar
{
    /// <summary>
    /// 
    /// </summary>
    public class PagerToolStrip : IPagerToolStrip
    {
        private readonly ICollection<IToolbar> _toolbars = new List<IToolbar>();
        private readonly int _pageSize;
        private readonly int _currentPage;
        private readonly int _totalItemCount;
        private string _pageQueryStringName = "page";
        private string _pageSizeQueryStringName = "pageSize";
        private string _sortQueryStringName = "sort";
        private string _sortOrderQueryStringName = "order";
        private string _first = "First";
        private string _previous = "Previous";
        private string _next = "Next";
        private string _last = "Last";
        private string _format = "Showing {0} to {1} of {2}";
        private string _singlePageFormat = "Showing {0} of {0}";
        private bool _keepPagesize;
        
        private ViewContext _viewContext;
        private readonly RouteValueDictionary _linkWithoutPageValuesDictionary;
        
        private string _id;
        private string _gridId;
        private string _ajaxUrl;
        private ICollection<ColumnModel> _columnModels = new List<ColumnModel>();

        public PagerToolStrip(ViewContext viewContext, int pageSize, int currentPage, int totalItemCount, RouteValueDictionary valuesDictionary)
        {
            // TODO use that and routeValues
            _viewContext = viewContext;
            _pageSize = pageSize;
            _totalItemCount = totalItemCount;

            if (currentPage < 1)
                currentPage = 1;
            if (currentPage * pageSize > totalItemCount)
                currentPage = LastPage;

            _currentPage = currentPage;
            _linkWithoutPageValuesDictionary = valuesDictionary;
        }

        public int PageSize { get { return _pageSize; } }
        public int CurrentPage { get { return _currentPage; } }
        public int TotalItemCount { get { return _totalItemCount; } }
        public int LastPage { get { return (int)Math.Ceiling(_totalItemCount / (float)_pageSize); } }
        public string PageParamName { get { return _pageQueryStringName; } }
        public string PageSizeParamName { get { return _pageSizeQueryStringName; } }
        public string SortParamName { get { return _sortQueryStringName; } }
        public string SortOrderParamName { get { return _sortOrderQueryStringName; } }
        public string FirstText { get { return _first; } }
        public string PreviousText { get { return _previous; } }
        public string NextText { get { return _next; } }
        public string LastText { get { return _last; } }
        public string FormatText { get { return _format; } }
        public string SinglePageFormatText { get { return _singlePageFormat; } }
        public string Id { get { return _id; } }
        public string GridId { get { return _gridId; } }

        public bool HasPreviousPage { get { return _currentPage > 1; } }
        public bool HasNextPage { get { return _currentPage * _pageSize < _totalItemCount; } }
        public bool UseAjaxUrl { get { return !string.IsNullOrEmpty(_ajaxUrl); } }
        public string Path { get { return _viewContext.RequestContext.HttpContext.Request.Path; } }
        
        /// <summary>
        /// Adds the specified toolbar.
        /// </summary>
        /// <param name="toolbar">The toolbar.</param>
        /// <returns></returns>
        public IPagerToolStrip AddToolbar(IToolbar toolbar)
        {
            toolbar.ToolStrip = this;
            _toolbars.Add(toolbar);
            return this;
        }

		/// <summary>
        /// Specifies the query string parameter name to use when generating pager links. The default is 'page'
		/// </summary>
        public IPagerToolStrip PageQueryStringName(string pageQueryStringName)
        {
            _pageQueryStringName = pageQueryStringName;
			return this;
        }

        /// <summary>
        /// Specifies the query string parameter name to use when generating pager links. The default is 'pageSize'
        /// </summary>
        /// <param name="pageSizeQueryStringName">Name of the page size query string parameter.</param>
        /// <returns></returns>
        public IPagerToolStrip PageSizeQueryStringName(string pageSizeQueryStringName)
        {
            _pageSizeQueryStringName = pageSizeQueryStringName;
            return this;
        }

        /// <summary>
        /// Specifies the query string parameter name to use when generating pager links. The default is 'sort'
        /// </summary>
        /// <param name="sortQueryStringName">Name of the sort query string parameter.</param>
        /// <returns></returns>
        public IPagerToolStrip SortQueryStringName(string sortQueryStringName)
        {
            _sortQueryStringName = sortQueryStringName;
            return this;
        }

        /// <summary>
        /// Specifies the query string parameter name to use when generating pager links. The default is 'order'
        /// </summary>
        /// <param name="sortOrderQueryStringName">Name of the sort order query string parameter.</param>
        /// <returns></returns>
        public IPagerToolStrip SortOrderQueryStringName(string sortOrderQueryStringName)
        {
            _sortOrderQueryStringName = sortOrderQueryStringName;
            return this;
        }

        /// <summary>
        /// Text or title for the 'first' link/button. The default is 'First'.
        /// </summary>
        /// <param name="first">The text or title for the 'first' link/button.</param>
        /// <returns>The <see cref="PagerToolStrip"/></returns>
        public IPagerToolStrip First(string first)
        {
            _first = first;
            return this;
        }

        /// <summary>
        /// Text or title for the 'previous' link/button. The default is 'Previous'.
        /// </summary>
        /// <param name="previous">The text or title for the 'previous' link/button.</param>
        /// <returns>The <see cref="PagerToolStrip"/></returns>
        public IPagerToolStrip Previous(string previous)
        {
            _previous = previous;
            return this;
        }

        /// <summary>
        /// Text or title for the 'next' link/button. The default is 'Next'.
        /// </summary>
        /// <param name="next">The text or title for the 'next' link/button.</param>
        /// <returns>The <see cref="PagerToolStrip"/></returns>
        public IPagerToolStrip Next(string next)
        {
            _next = next;
            return this;
        }

        /// <summary>
        /// Text or title for the 'last' link/button. The default is 'Last'.
        /// </summary>
        /// <param name="last">The text or title for the 'last' link/button.</param>
        /// <returns>The <see cref="PagerToolStrip"/></returns>
        public IPagerToolStrip Last(string last)
        {
            _last = last;
            return this;
        }

        /// <summary>
        /// Specifies the format to use when rendering a pagination containing multiple pages. 
        /// The default is 'Showing {0} - {1} of {2}' (eg 'Showing 1 to 10 of 16')
        /// </summary>
        public IPagerToolStrip Format(string format)
        {
            _format = format;
            return this;
        }

        /// <summary>
        /// Specifies the format to use when rendering a pagination containing a single page. 
        /// The default is 'Showing {0} of {0}' (eg 'Showing 3 of 3')
        /// </summary>
        public IPagerToolStrip SinglePageFormat(string format)
        {
            _singlePageFormat = format;
            return this;
        }

        public IPagerToolStrip WithId(string id)
        {
            _id = id;
            return this;
        }

        public IPagerToolStrip WithGridId(string gridId)
        {
            _gridId = gridId;
            return this;
        }

        public IPagerToolStrip AjaxUrl(string url)
        {
            _ajaxUrl = url;
            return this;
        }

        public IPagerToolStrip ColModel(Action<ColumnModelBuilder> columnModelBuilder)
        {
            var builder = new ColumnModelBuilder();
            columnModelBuilder(builder);

            foreach (var columnModel in builder)
            {
                _columnModels.Add(columnModel);
            }

            return this;
        }

        public IPagerToolStrip KeepPageSize()
        {
            _keepPagesize = true;
            return this;
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();

            // TODO toolstrip attributes, define standard class
            string id = _id == null ? string.Empty : string.Format("id=\"{0}\" ", _id);
            sb.AppendLine(string.Format("<div {0}class=\"{1}\">", id, "tStrip"));

            foreach (var toolbar in _toolbars)
            {
                // TODO toolbar attributes, define standard class
                sb.Append(string.Format("<div class=\"{0}\">", "tBar"));

                foreach (var toolbarItem in toolbar.Items)
                    sb.Append(toolbarItem.GetValue());

                sb.Append("</div>");
            }

            sb.AppendLine("</div>");

        // Emit the jQuery script to call the pager plugin if needed
            /*
            <script type="text/javascript">
                $(document).ready(function() {
                    $('#pgrC').pager({
                        pages: 15,
                        gridId: 'C',
                        url: '<%= Url.Content("~/Grid/Customers") %>',
                        pagestat: 'Showing {from} to {to} of {total} customers',
                        singlepagestat: 'Showing {from} of {total} customers',
                        keepPs: 1,
                        colModel: [
                            { key: 'id' },
                            { key: 'firstname' }, 
                            { key: 'lastname' }]
                    });
                });
            </script>
            */

            if (UseAjaxUrl)
            {
                sb.AppendLine("<script type='text/javascript'>");
                sb.AppendLine("$(document).ready(function() {");
                sb.AppendLine(string.Format("$('#{0}').pagerOptions({{", _id));
                sb.AppendLine(string.Format("pages: {0},", LastPage));
                sb.AppendLine(string.Format("gridId: '{0}',", _gridId));
                sb.AppendLine(string.Format("url: '{0}',", _ajaxUrl));
                string pagestat = _format;
                pagestat = pagestat.Replace("{0}", "{from}");
                pagestat = pagestat.Replace("{1}", "{to}");
                pagestat = pagestat.Replace("{2}", "{total}");
                sb.AppendLine(string.Format("pagestat: '{0}',", pagestat));
                pagestat = _singlePageFormat;
                pagestat = pagestat.Replace("{0}", "{from}");
                pagestat = pagestat.Replace("{1}", "{to}");
                pagestat = pagestat.Replace("{2}", "{total}");
                if (_columnModels.Count > 0)
                {
                    sb.AppendLine("colModel: [");
                    string colModelFormat = "key:'{0}'{1}";
                    foreach (var columnModel in _columnModels)
                    {
                        sb.Append("{");
                        
                        string format = string.Empty;

                        if (!string.IsNullOrEmpty(columnModel.FormatString))
                        {
                            format = ",format:'{0}'{1}";
                            string formatKey = string.Empty;
                            if ( !string.IsNullOrEmpty(columnModel.FormatKey))
                            {
                                formatKey = string.Format(",formatKey:'{0}'", columnModel.FormatKey);
                            }

                            string formatString = columnModel.FormatString.Replace("'", "\"");
                            format = string.Format(format, formatString, formatKey);
                        }

                        sb.AppendFormat(colModelFormat, columnModel.Key, format);
                        sb.Append("},");
                    }
                    // Cut off the last comma
                    sb.Remove(sb.Length - 1, 1);
                    sb.AppendLine("],");
                }
                if (_keepPagesize)
                    sb.AppendLine("keepPs: 1,");
                sb.AppendLine(string.Format("singlepagestat: '{0}'", pagestat));
                sb.AppendLine("});");
                sb.AppendLine("});");
                sb.AppendLine("</script>");
            }

            return sb.ToString();
        }

        public string GetQueryStringValue(string key)
        {
            string value = null;
            HttpRequestBase request = _viewContext.RequestContext.HttpContext.Request;

            foreach (string k in request.QueryString.Keys)
            {
                if (k.ToLower().Equals(key, StringComparison.InvariantCultureIgnoreCase))
                {
                    value = request.QueryString[k];
                    break;
                }
            }

            return value;
        }

        public string GetPagingUrl(int page)
        {
            string url = Path;

            if (url.Contains("?"))
                url += "&";
            else
                url += "?";

            string sortParam = GetQueryStringValue(SortParamName);
            string sortOrderParam = GetQueryStringValue(SortOrderParamName);

            url += string.Format("{0}={1}&{2}={3}&{4}={5}&{6}={7}",
                                 PageParamName,
                                 page,
                                 PageSizeParamName,
                                 PageSize,
                                 SortParamName,
                                 sortParam,
                                 SortOrderParamName,
                                 sortOrderParam);
            return url;
        }
    }
}
